#Copyright (c) Hans Andersson 2011

import NeuralNetwork

class Decision:
	def __init__(self, context, outputsType, outputsCount = 1, description = None):
		#context : recursive float dictionary
		#outputsType : string
		#outputsCount : (int)
		#description : (string)
		self.context = context
		self.outputsType = outputsType
		self.outputsCount = outputsCount
		self.activations = None
		self.description = description
	
	def through(self, brain):
		#brain : Brain
		self.activations = brain.feedForward(NeuralNetwork.Stimulus.fromDict(self.context), self.outputsType, self.outputsCount)
		assert len(self.activations) == self.outputsCount
		return self.activations

#I've found that the neural nets can learn discrete decisions much better than continuous ones
class Enumeration(Decision):
	class Option:
		def __init__(self, context, outputsType, id = None, description = None):
			#context : recursive float dictionary
			#outputsType : string
			#id : (any) #for external identification only---not for use in NeuralNetwork
			#description (string)
			self.context = context
			self.outputsType = outputsType
			self.id = id
			self.activations = None
			self.description = description
	
	def __init__(self, context, outputsType, description = None):
		#context : recursive float dictionary
		#outputsType : string
		#description : (string)
		self.context = context
		self.outputsType = outputsType
		self.outputsCount = 1
		self.activations = None
		self.options = []
		self.description = description
	
	def option(self, context, outputsType, id = None, description = None):
		#context : recursive float dictionary
		#outputsType : string
		#id : (any)
		#description : (string)
		option = self.__class__.Option(context, outputsType, id, description)
		self.options.append(option)
		return option
	
	def selection(self):
		return reduce(lambda selection, option: selection if selection.activation > option.activation else option, self.options)
	
	def through(self, brain):
		#brain : Brain
		for option, representation in zip(self.options, self.toDicts()):
			option.activation = brain.feedForward(NeuralNetwork.Stimulus.fromDict(representation), self.outputsType, 1)
			assert len(option.activation) == 1
		return self.selection()
	
	def toDicts(self):
		return [{"context":self.context, option.outputsType:option.context} for option in self.options]

class Validation(Decision):
	def __init__(self, context, outputsType, description = None):
		self.context = context
		self.outputsType = outputsType
		self.outputsCount = 1
		self.activations = None
		self.description = description
		
	def selection(self):
		assert self.activations != None
		assert type(self.activations) == type(list())
		assert len(self.activations) == 1
		return self.activations[0] > 0.5